package com.example.testdemoutils.dynamic_data_source.aop;

import com.example.testdemoutils.dynamic_data_source.config.DynamicContextHolder;
import com.example.testdemoutils.dynamic_data_source.config.DynamicDataSource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * @Description: 动态加载多数据源（启动后加载）
 **/
@Aspect
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@Slf4j
public class DynamicDataSourceAspect {

    @Pointcut("@annotation(com.example.testdemoutils.dynamic_data_source.aop.DynamicDataSource) " +
            "|| @within(com.example.testdemoutils.dynamic_data_source.aop.DynamicDataSource)")
    public void dynamicdataSourcePointCut() {

    }

    @Around("dynamicdataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        //获取参数，根据参数获取数据源
        String dbKey = getDbKey(point);

        if (dbKey != null) {
            //根据dbKey动态设置数据源
            DynamicDataSource.setDataSource(dbKey);
        }
        try {
            return point.proceed();
        } finally {
            DynamicContextHolder.poll();
            log.debug("clean datasource");
        }
    }


    /**
     * 根据@DbKey注解获取数据源的dbKey
     *
     * @param point
     * @return
     */
    private String getDbKey(ProceedingJoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Object[] args = point.getArgs();
        String value = null;
        //参数注解，1维是参数，2维是注解
        Annotation[][] annotations = method.getParameterAnnotations();
        for (int i = 0; i < annotations.length; i++) {
            Object param = args[i];
            Annotation[] paramAnn = annotations[i];
            //参数为空，直接下一个参数
            if (param == null) {
                continue;
            }
            for (Annotation pAnnotation : paramAnn) {
                if (pAnnotation.annotationType().equals(DbKey.class)) {
                    value = param.toString();
                    break;
                }
            }
        }
        return value;
    }
}

